﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using ShootSearch.Util;
using ShootSearch.Util.Serializers;

namespace ShootSearch.Common
{
    /// <summary>
    /// 将UrlQueue和BloomFilter组合在一起成为一个HashList
    /// 只能增加,不能减少元素
    /// </summary>
    [Serializable]
    public class UrlHashList
    {
        /// <summary>
        /// BloomFilter对象,用于标记某个Url是否处理过
        /// </summary>
        private BloomFilter bloom;
        /// <summary>
        /// Url队列,用于存储处理过的Url队列
        /// </summary>
        private UrlQueue queue;
        /// <summary>
        /// BloomFilter表长度
        /// </summary>
        private int tableSize;
        //private int nKeys;
        /// <summary>
        /// 缓冲区路径
        /// </summary>
        private string cachepath;
        /// <summary>
        /// 线程锁
        /// </summary>
        private object locker = new object();

        /// <summary>
        /// 缓冲区路径
        /// </summary>
        [XmlIgnore]
        public string CachePath
        {
            get 
            {
                //如果没有赋值就返回默认值
                if (string.IsNullOrEmpty(cachepath))
                    return DefaultCachePath;
                else
                    return cachepath; 
            }
            set 
            {
                cachepath = IO.FormatDirName(value);
                queue.CachePath = cachepath;
            }
        }

        /// <summary>
        /// 队列的最大长度，当超过此长度时需要把多余的内容写入磁盘
        /// </summary>
        [XmlIgnore]
        public int BlockLength
        {
            get
            {
                if (queue != null) return queue.BlockLength;
                else return 50000;
            }
            set
            {
                if (queue != null) queue.BlockLength = value;
            }
        }

        /// <summary>
        /// 长度
        /// </summary>
        [XmlIgnore]
        public long Length 
        {
            get 
            {
                if (queue == null)
                    return 0;
                else
                    return queue.Length;
            }
        }

        /// <summary>
        /// BloomFilter表长(只读)
        /// </summary>
        public int TableSize
        {
            get { return tableSize; }
        }

        /// <summary>
        /// 初始化方法,供内部的构造函数调用
        /// </summary>
        /// <param name="tableSize">BloomFilter表长</param>
        /// <param name="path">缓冲区路径</param>
        private void Init(int tableSize, string path)
        {
            this.tableSize = tableSize;
            this.cachepath = path;
            bloom = new BloomFilter(tableSize);
            queue = new UrlQueue(path);
        }

        /// <summary>
        /// 无参构造,只用于序列化使用
        /// </summary>
        public UrlHashList()
        {
            queue = new UrlQueue();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="tableSize">BloomFilter表长</param>
        public UrlHashList(int tableSize)
        {
            Init(tableSize, DefaultCachePath);
        }

        /// <summary>
        /// 默认路径
        /// </summary>
        private string DefaultCachePath
        {
            get { return IO.FormatDirName(Application.StartupPath + "\\Cache\\"); }
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="tableSize">BloomFilter表长</param>
        /// <param name="path">缓冲区路径</param>
        public UrlHashList(int tableSize, string path)
        {
            Init(tableSize, path);
        }

        /// <summary>
        /// 检测某一个Url项是否已经包含在HashList中
        /// </summary>
        /// <param name="url">要检查的Url</param>
        /// <returns>true 已经包含</returns>
        public bool Contains(string url)
        {
            return bloom.Contains(url);
        }

        /// <summary>
        /// 添加一个元素
        /// </summary>
        /// <param name="url">要增加的Url</param>
        /// <returns>False 成功添加</returns>
        public bool Add(Url url)
        {
            lock (locker)
            {
                queue.EnQueue(url);
                return bloom.Add(url.Address);
            }
        }

        /// <summary>
        /// 清空所有的Key的值
        /// 这样就可以继续存储,处理过的队列仍然有效
        /// </summary>
        public void ClearKeys()
        {
            bloom = new BloomFilter(tableSize, 3);
        }

        /// <summary>
        /// 全部清空
        /// </summary>
        public void ClearAll()
        {
            ClearKeys();
            queue.Clear();
        }

        /// <summary>
        /// 保存
        /// </summary>
        public void Save()
        {
            lock (locker)
            {
                //首先保存BloomFilter
                XmlFormatter.SerializeBinary(bloom, cachepath + "BloomFilter.Save");
                //保存队列
                queue.Save();
                //保存自己
                XmlFormatter.SerializeBinary(this, cachepath + "HashList.Save");
            }
        }

        /// <summary>
        /// 从默认的路径加载
        /// </summary>
        /// <returns>HashList对象</returns>
        public static UrlHashList Load()
        {
            return Load(IO.FormatDirName(Application.StartupPath + "\\Cache\\"));
        }

        /// <summary>
        /// 加载
        /// </summary>
        /// <param name="path">要加载的路径</param>
        /// <returns>HashList对象</returns>
        public static UrlHashList Load(string path)
        {
            path = IO.FormatDirName(path, true);
            UrlHashList hash = new UrlHashList(1,path);
            hash = (UrlHashList)XmlFormatter.DeserializeBinary(path + "HashList.Save");
            hash.bloom = (BloomFilter)XmlFormatter.DeserializeBinary(path + "BloomFilter.Save");
            hash.queue = new UrlQueue(path);
            hash.queue.Load();
            return hash;
        }
    }

}
